home *** CD-ROM | disk | FTP | other *** search
- /*
- * eight.c : 8パズルの解法(メモリは約 5 M Byte 必要)
- *
- * Copyright (C) 1999 by Makoto Hiroi
- *
- * 座標 完成形
- * 0 1 2 1 2 3
- * 3 4 5 4 5 6
- * 6 7 8 7 8 0 : 0 は空白を表す
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <time.h>
-
- /* 状態数 (9! / 2) */
- #define S_SIZE 181440
- #define B_SIZE 9
- #define MAX_MOVE 31
-
- #define TRUE 1
- #define FALSE 0
-
- /* 状態(二分木を構成する) */
- typedef struct {
- char board[B_SIZE];
- short zp; /* 0 の位置 */
- int prev;
- int right;
- int left;
- } State;
-
- /* 状態数を格納するテーブル(約 4.4 M byte) */
- State state_table[S_SIZE];
-
- /* n 手目が始まるステート番号を記憶 */
- int move_table[MAX_MOVE + 1];
-
- /* 隣接リスト */
- short adjacent[9][5] = {
- 1, 3,-1,-1,-1,
- 0, 4, 2,-1,-1,
- 1, 5,-1,-1,-1,
- 0, 4, 6,-1,-1,
- 1, 3, 5, 7,-1,
- 2, 4, 8,-1,-1,
- 3, 7,-1,-1,-1,
- 4, 6, 8,-1,-1,
- 5, 7,-1,-1,-1,
- };
-
- /* 終了状態 */
- char end_state[B_SIZE] = {1,2,3,4,5,6,7,8,0};
-
- /* 追加する */
- int insert_tree( int i )
- {
- int n = 0;
- while( 1 ){
- int next;
- int r = memcmp( state_table[i].board, state_table[n].board, B_SIZE );
- if( r == 0 ){
- /* 登録済み */
- return FALSE;
- } else if( r < 0 ){
- /* 左へたどる */
- if( (next = state_table[n].left) == -1 ){
- state_table[n].left = i;
- return TRUE;
- }
- } else {
- /* 右へたどる */
- if( (next = state_table[n].right) == -1 ){
- state_table[n].right = i;
- return TRUE;
- }
- }
- n = next;
- }
- }
-
- /* 初期化 */
- void init( char *init_state )
- {
- int i = 0;
- char *ptr = state_table[0].board;
- for( ; i < B_SIZE; i++ ){
- if( (*ptr++ = *init_state++) == 0 ){
- state_table[0].zp = i;
- }
- }
- state_table[0].prev = -1;
- state_table[0].left = -1;
- state_table[0].right = -1;
- move_table[0] = 0;
- }
-
- /* 盤面を表示する */
- void print_board( char *b )
- {
- int i;
- for( i = 0; i < B_SIZE; i++ ){
- printf("%d ", b[i] );
- if( i == 2 || i == 5 ) printf("\n");
- }
- printf("\n\n");
- }
-
- /* 手順を表示 */
- void print_history( int num )
- {
- print_board( end_state );
- while( num != -1 ){
- print_board( state_table[num].board );
- num = state_table[num].prev;
- }
- }
-
- /* 探索関数 */
- int search( char *init_state )
- {
- int move = 1, count = 1;
- init( init_state );
- while( count > move_table[move - 1] ){
- int i = move_table[move - 1];
- printf("%d 手の検索:局面数 %d 個\n", move, count ); fflush( stdout );
- move_table[move] = count;
- for( ; i < move_table[move]; i++ ){
- short zp = state_table[i].zp;
- char *b = state_table[i].board;
- short *p = adjacent[zp];
- for( ; *p != -1; p++ ){
- /* 盤面をコピー */
- char *b1 = state_table[count].board;
- memcpy( b1, b, B_SIZE );
- /* 駒の移動 */
- b1[zp] = b1[*p];
- b1[*p] = 0;
-
- if( !memcmp( end_state, b1, B_SIZE ) ){
- /* 解けた */
- print_history( i );
- return TRUE;
- } else if( insert_tree( count ) ){
- /* 二分木に追加できたので同じ状態はない */
- state_table[count].zp = *p;
- state_table[count].prev = i;
- state_table[count].left = -1;
- state_table[count++].right = -1;
- }
- }
- }
- /* 次の移動 */
- move++;
- }
- return FALSE;
- }
-
- volatile void usage( void )
- {
- fprintf( stderr, "usage : eight state\n state は 0 - 8 の数字を一つずつ ex 123456708\n" );
- exit( 1 );
- }
-
- int main( int argc, char *argv[] )
- {
- int i, start;
- char init_state[B_SIZE];
- if( argc != 2 ){
- usage();
- }
- /* 初期の配置を取得 */
- for( i = 0; i < B_SIZE; i++ ){
- int n = argv[1][i];
- if( !isdigit( n ) || n == '9' ) usage();
- n = n - '0';
- if( i > 0 && memchr( init_state, n, i ) != NULL ) usage(); /* 同じ数字が使われている */
- init_state[i] = n;
- }
- /* 検索開始 */
- start = clock();
- search( init_state );
- printf("時間 %d\n", clock() - start );
- return 0;
- }
-
- /* end of file */
-
-